﻿using WzhModule.GM.UI;
using System.Collections.Generic;
using System.Reflection;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.UI;

namespace WzhModule.GM
{
    public partial class WzhGMPanel
    {

        public static float TabWidthFactor = 0.2f;
        //public static float ButtonWidthFactor = 0.8f;
        //public static float LabelWidthFactor = 0.8f;
        //public static float ToogleWidthFactor = 0.8f;


        public static float TabHeightFactor = 0.05f;
        public static float ButtonHeightFactor = 0.05f;
        public static float LabelHeightFactor = 0.04f;
        public static float ToogleHeightFactor = 0.05f;

        public float ElementWidth => WzhGMControl.CanvasWidth;
        public float ElementHeight => WzhGMControl.CanvasHeight;

        protected void AddToggleButton(UnityAction<int, bool> action, int id, string toggleName, bool value, MemberInfo memberInfo)
        {
            GameObject go = GetNextUnusedButton(ToggleButtons);
            if (go == null)
            {
                go = Instantiate(TogglePrefab);
                go.transform.SetParent(ButtonsParent.transform, false);
                ToggleButtons.Add(go);
            }
            else
            {
                go.SetActive(true);
            }

            WzhGMToggle toggle = go.GetComponent<WzhGMToggle>();
            toggle.Clear();
            toggle.isOn = value;
            toggle.AddAction(action, id);
            toggle.MemberInfo = memberInfo;

            //go.GetComponent<RectTransform>().sizeDelta = new Vector2(ElementWidth * ToogleWidthFactor, ElementHeight * ToogleHeightFactor);

            Text txt = go.GetComponentInChildren<Text>();
            txt.text = toggleName;
        }
        protected void AddSlider(UnityAction<int, float> action, int id, string sliderName, float minValue, float maxValue, float currentValue, bool isInt, float? size = null)
        {
            GameObject go = GetNextUnusedButton(ContentSliders);
            if (go == null)
            {
                go = Instantiate(SliderPrefab);
                go.transform.SetParent(ContentLayoutGroup.transform, false);
                ContentSliders.Add(go);
            }
            else
            {
                go.SetActive(true);
            }

            Text txt = go.transform.Find("txt_slider").GetComponent<Text>();
            _stb.Length = 0;
            _stb.Append(sliderName).Append(": ").Append(currentValue.ToString("0.00"));
            txt.text = _stb.ToString();

            WzhGMButton btnLeft = go.transform.Find("btn_left").GetComponent<WzhGMButton>();
            btnLeft.AddAction(CallSliderMethodButtons, id, false);

            WzhGMButton btnRight = go.transform.Find("btn_right").GetComponent<WzhGMButton>();
            btnRight.AddAction(CallSliderMethodButtons, id, true);


            WzhGMSlider slider = go.GetComponentInChildren<WzhGMSlider>();
            slider.Clear();
            slider.minValue = minValue;
            slider.maxValue = maxValue;
            if (size.HasValue)
            {
                RectTransform rt = slider.transform as RectTransform;
                rt.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, size.Value);
            }

            slider.value = currentValue;
            slider.wholeNumbers = isInt;
            slider.onValueChanged.RemoveAllListeners();
            slider.AddAction(action, id, sliderName);

        }
        protected void UpdateSliderText(int id, float value)
        {
            GameObject go = ContentSliders[id];
            _stb.Length = 0;
            _stb.Append(go.GetComponentInChildren<WzhGMSlider>().SliderInfo);
            _stb.Append(": ");
            _stb.Append(value.ToString("0.00"));
            go.transform.Find("txt_slider").GetComponent<Text>().text = _stb.ToString();
        }

        public virtual void Update()
        {
            if (!Opened) return;

            //We dynamically update all labels, so if the value changes, we see it immediatelly, without having to redraw the whole menu
            UpdateLabels();
            UpdateToggles();
        }

        private void UpdateLabels()
        {
            if (SelectedObject != null)
            { //Update every frame if there is a label present!
                for (int i = 0; i < LabelButtons.Count; i++)
                {
                    if (LabelButtons[i].activeSelf)
                    {

                        var uiLabel = LabelButtons[i].GetComponentInChildren<WzhGMUILabel>();
                        if (uiLabel.MemberInfo == null)
                        {
                            continue;
                        }
                        object value = GetValueFromMemberInfo(SelectedObject, uiLabel.MemberInfo);

                        string name = "";
                        WzhGMLabel[] attributes = (WzhGMLabel[])uiLabel.MemberInfo.GetCustomAttributes(typeof(WzhGMLabel), false);
                        if (attributes.Length > 0 && attributes[0].LabelName != null)
                        {
                            _stb.Length = 0;
                            _stb.Append(attributes[0].LabelName).Append(" ");
                            name = _stb.ToString();
                        }

                        var str_value = value == null ? "null" : value.ToString();
                        _stb.Length = 0;
                        _stb.AppendFormat("{0}:[{1}]",name,str_value);
                        string valueName = _stb.ToString();
                        uiLabel.text = valueName;
                    }
                }
            }
        }

        private void UpdateToggles()
        {
            if (SelectedObject != null)
            { //Update every frame if there is a label present!
                for (int i = 0; i < ToggleButtons.Count; i++)
                {
                    if (ToggleButtons[i].activeSelf)
                    {
                        var uiLabel = ToggleButtons[i].GetComponentInChildren<WzhGMToggle>();
                        object value = GetValueFromMemberInfo(SelectedObject, uiLabel.MemberInfo);

                        uiLabel.isOn = (bool)value;
                    }
                }
            }
        }

        protected virtual void OnDestroy()
        {
            //if (OnUiDestroyed != null) {
            //    OnUiDestroyed(this);
            //}
        }

        #region AddButton


        public void AddTalbeButton(UnityAction<int> action, int id, string text)
        {
            GameObject go = GetNextUnusedButton(TabButtons);
            WzhGMButton btn;
            Text txt;
            if (go == null)
            {
                go = Instantiate(BtnTablePrefab, TableParent).gameObject;
                TabButtons.Add(go);
            }
            _stb.Length = 0;
            _stb.Append("btn_").Append(name);
            go.name = _stb.ToString();
            go.SetActive(true);
            btn = go.GetComponent<WzhGMButton>();
            txt = go.GetComponentInChildren<Text>();
            btn.Clear();

            if (action != null)
            {
                btn.AddAction(action, id);
            }
            go.GetComponent<RectTransform>().sizeDelta = new Vector2(ElementWidth * TabWidthFactor, Screen.height * TabHeightFactor);

            txt.text = text;

        }


        protected void AddButton(UnityAction<int> Action, string text, int id)
        {
            GameObject go = GetNextUnusedButton(ContentButtons);
            WzhGMButton btn;
            Text txt;

            if (go == null)
            {
                go = Instantiate(BtnPrefab, ButtonsParent.transform).gameObject;
                btn = go.GetComponent<WzhGMButton>();
                txt = go.GetComponentInChildren<Text>();
                ContentButtons.Add(go);
            }
            else
            {
                go.SetActive(true);
                btn = go.GetComponent<WzhGMButton>();
                txt = go.GetComponentInChildren<Text>();
                btn.Clear();
            }
            //go.GetComponent<RectTransform>().sizeDelta = new Vector2(ElementWidth * ButtonWidthFactor, ElementHeight * ButtonHeightFactor);
            if (Action != null)
            {
                btn.AddAction(Action, id);
            }
            txt.text = text;
        }


        /// <summary>添加小窗的按钮</summary>
        protected void AddMiniButton(UnityAction<int> Action, string text, int id)
        {
            GameObject go = GetNextUnusedButton(MiniButtons);
            WzhGMButton btn;
            Text txt;

            if (go == null)
            {
                go = Instantiate(MiniBtnPrefab, MiniButtonsParent.transform).gameObject;
                btn = go.GetComponent<WzhGMButton>();
                txt = go.GetComponentInChildren<Text>();
                MiniButtons.Add(go);
            }
            else
            {
                go.SetActive(true);
                btn = go.GetComponent<WzhGMButton>();
                txt = go.GetComponentInChildren<Text>();
                btn.Clear();
            }
            //go.GetComponent<RectTransform>().sizeDelta = new Vector2(ElementWidth * ButtonWidthFactor, ElementHeight * ButtonHeightFactor);
            if (Action != null)
            {
                btn.AddAction(Action, id);
            }
            txt.text = text;
        }


        private void AddLabel(string text, MemberInfo memberInfo)
        {
            GameObject go = GetNextUnusedButton(LabelButtons);
            WzhGMUILabel label;

            if (go == null)
            {
                go = Instantiate(LabelPrefab);
                go.transform.SetParent(LabelsParent.transform, false);
                label = go.transform.Find("txt").GetComponent<WzhGMUILabel>();
                LabelButtons.Add(go);
            }
            else
            {
                go.SetActive(true);
                label = go.transform.Find("txt").GetComponent<WzhGMUILabel>();
            }
            //go.GetComponent<RectTransform>().sizeDelta = new Vector2(ElementWidth * LabelWidthFactor, ElementHeight * LabelHeightFactor);
            label.MemberInfo = memberInfo;

            label.text = text;
        }

        protected GameObject GetNextUnusedButton(List<GameObject> list)
        {
            for (int i = 0; i < list.Count; i++)
            {
                if (!list[i].activeSelf)
                {
                    return list[i];
                }
            }
            return null;
        }
        #endregion

        #region 左边和右边按钮



        public void ShowLeftAndRightPanel()
        {
            for (int i = 0; i < LeftButtons.Count; i++)
            {
                LeftButtons[i].SetActive(false);
            }

            for (int i = 0; i < RightButtons.Count; i++)
            {
                RightButtons[i].SetActive(false);
            }


            //draw left panel button
            if (Buttons.ContainsKey(LeftDebuggableObject))
            {
                var leftBtns = Buttons[LeftDebuggableObject];
                for (int i = 0; i < leftBtns.Count; i++)
                {
                    string buttonName = leftBtns[i].Name;
                    WzhGMMethod[] attrs = (WzhGMMethod[])leftBtns[i].GetCustomAttributes(typeof(WzhGMMethod), false);
                    if (attrs.Length > 0 && !string.IsNullOrEmpty(attrs[0].ButtonName))
                    {
                        buttonName = attrs[0].ButtonName;
                    }
                    AddLeftOrRightButton(CallLeftDebugMethod, buttonName, i, true);
                }
            }

            //draw right panel button
            if (Buttons.ContainsKey(RightDebuggableObject))
            {
                var rightBtns = Buttons[RightDebuggableObject];
                for (int i = 0; i < rightBtns.Count; i++)
                {
                    string buttonName = rightBtns[i].Name;
                    WzhGMMethod[] attrs = (WzhGMMethod[])rightBtns[i].GetCustomAttributes(typeof(WzhGMMethod), false);
                    if (attrs.Length > 0 && !string.IsNullOrEmpty(attrs[0].ButtonName))
                    {
                        buttonName = attrs[0].ButtonName;
                    }
                    AddLeftOrRightButton(CallRightDebugMethod, buttonName, i, false);
                }
            }

        }

        private void CallLeftDebugMethod(int id)
        {
            var button = LeftButtons[id];
            var buttonText = button.GetComponentInChildren<Text>().text;
            _stb.Length = 0;
            _stb.Append(Tag).Append("---").Append(buttonText).Append(" button pressed");
            WzhGMControl.I.Log(_stb);

            var i = Buttons[LeftDebuggableObject][id];
            i.Invoke(LeftDebuggableObject, null);
        }

        private void CallRightDebugMethod(int id)
        {
            var button = RightButtons[id];
            var buttonText = button.GetComponentInChildren<Text>().text;
            _stb.Length = 0;
            _stb.Append(Tag).Append("---").Append(buttonText).Append(" button pressed");
            WzhGMControl.I.Log(_stb);

            var i = Buttons[RightDebuggableObject][id];
            i.Invoke(RightDebuggableObject, null);
        }


        protected void AddLeftOrRightButton(UnityAction<int> tabAction, string text, int id, bool isLeftOrRightPnl)
        {
            GameObject go = isLeftOrRightPnl ? GetNextUnusedButton(LeftButtons) : GetNextUnusedButton(RightButtons);
            GameObject txtGo;
            WzhGMButton btn;
            Text txt;

            if (go == null)
            {
                go = new GameObject();
                go.layer = LayerMask.NameToLayer("UI");
                _stb.Length = 0;
                _stb.Append("btn_").Append(name);
                go.name = _stb.ToString();
                go.transform.SetParent(isLeftOrRightPnl ? LeftLayoutGroup.transform : RightLayoutGroup.transform, false);
                btn = SetSidingButton(go);

                txtGo = new GameObject();
                txtGo.layer = LayerMask.NameToLayer("UI");
                txtGo.transform.SetParent(go.transform, false);
                _stb.Length = 0;
                _stb.Append("txt_").Append(name);
                txtGo.name = _stb.ToString();

                var txtRT = txtGo.AddComponent<RectTransform>();
                var txtUi = txtGo.AddComponent<Text>();
                txt = SetText(txtRT, txtUi);

                if (isLeftOrRightPnl)
                {
                    LeftButtons.Add(go);
                }
                else
                {
                    RightButtons.Add(go);
                }
                LayoutElement le = go.AddComponent<LayoutElement>();
                le.minHeight = 100;
            }
            else
            {
                go.SetActive(true);
                btn = go.GetComponent<WzhGMButton>();
                txt = go.GetComponentInChildren<Text>();
                btn.Clear();
            }

            if (tabAction != null)
            {
                btn.AddAction(tabAction, id);
            }
            txt.text = text;
        }

        protected WzhGMButton SetSidingButton(GameObject go)
        {
            Image img = go.AddComponent<Image>();
            img.sprite = ButtonSprite;
            img.color = new Color(1, 1, 1, 0.3f);
            WzhGMButton btn = go.AddComponent<WzhGMButton>();
            btn.transition = Selectable.Transition.SpriteSwap;
            SpriteState st = new SpriteState();
            st.pressedSprite = ButtonPressedSprite;
            st.highlightedSprite = ButtonHighlightSprite;
            btn.spriteState = st;

            return btn;
        }
        protected Text SetText(RectTransform txtRT, Text txt)
        {
            txtRT.anchorMin = Vector2.zero;
            txtRT.anchorMax = Vector2.one;
            txtRT.offsetMin = Vector2.zero;
            txtRT.offsetMax = Vector2.zero;

            txt.color = Color.white;
            txt.resizeTextForBestFit = true;
            txt.resizeTextMinSize = 20;
            txt.resizeTextMaxSize = 50;
            txt.fontSize = 30;
            txt.alignment = TextAnchor.MiddleCenter;
            txt.font = DebugFont;
            return txt;
        }
        #endregion

    }
}
